# -*- coding: utf-8 -*-

import time
import copy
import threading
import random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from adatper import data_bridge
from math import pi


class place():
    def __init__(self):
        self.gridScale = 2  # 遍历时使用的栅格的放大倍数
        self.gridX = 20  # 排布时的X范围
        self.gridY = 30  # Y
        self.grids = None  # 栅格:0代表未使用，1代表使用

    def initGrid(self):
        # 地图是横着放的,左下角是（40,0）右上角是（0,50）
        k = np.zeros((self.gridX + 1) * (self.gridY + 1)).reshape([self.gridX + 1, self.gridY + 1])
        k[0] = 0.5
        k[-1] = 0.5
        k.T[0] = 0.5
        k.T[-1] = 0.5
        self.grids = k

    def refeshGrid_rect(self, grids, graph):
        for x in range(graph[0][0], graph[2][0]):
            for y in range(graph[0][1], graph[2][1]):
                # flag = self.judgePointInner(i, j, graph)
                if x == graph[0][0] or x == graph[2][0] or y == graph[0][1] or y == graph[2][1]:  # 边重叠加0.5
                    grids[x, y] += 0.5
                else:  # 内部直接为1
                    grids[x, y] += 1

                if grids[x, y] > 1:
                    return False  # 边界重叠
        for point in graph:  # 将角点重置为0.5
            up_point = point + [0, 1]
            right_point = point + [1, 0]
            down_point = point - [0, 1]
            try:
                if grids[up_point[0], up_point[1]] < 1 or grids[right_point[0], right_point[1]] < 1:
                    grids[point[0], point[1]] = 0.5
            except Exception as e:
                pass
        # 测试用，显示每个点的状态
        # print(graph)
        # for i in range(cover0[0], cover1[0] + 1):
        #     for j in range(cover0[1], cover1[1] + 1):
        #         print(i,j, grids[i,j])
        # input()
        return grids

    # 返回FF装箱的矩形摆放
    def FF_place(self, grids, rects):
        cursor = 0  # 控制原始图形和rt的游标
        stop = len(rects)  # 游标停止标识
        rt = copy.deepcopy(rects)

        while cursor < stop:
            breakFlag = False
            for y in range(grids.shape[1]):
                if breakFlag:
                    break
                for x in range(grids.shape[0]):
                    if breakFlag:
                        break

                    this_point = grids[x, y]
                    if this_point >= 1:  # 该点已经被占领
                        continue
                    graph = rects[cursor]

                    blank = -1
                    for _cursor in range(x, self.gridX + 1):
                        if grids[_cursor, y] < 1:
                            blank += 1
                        else:
                            break
                    if blank < graph[1, 0] - graph[0, 0]:  # 该空隙放不下
                        continue

                    mov_x = graph[0, 0] - x
                    mov_y = graph[0, 1] - y
                    new_graph = graph - [mov_x, mov_y]  # 平移图形
                    if new_graph[1, 0] >= self.gridX + 1 or new_graph[0, 1] >= self.gridY + 1:  # 超界
                        continue
                    # 重叠检测放到refeshGrid里面去做
                    # for x in range(new_graph[0][0], new_graph[2][0]):
                    #     for y in range(new_graph[0][1], new_graph[2][1]):
                    #         if grids[x, y] >= 1:
                    #             new_graph[1,0] = 999    # 边界重叠
                    new_grids = self.refeshGrid_rect(grids, new_graph)  # 刷新栅格同时检测是否有重叠，有则返回F
                    if new_grids is False:  # 重叠
                        continue
                    else:
                        grids = new_grids  # 同步
                        rt[cursor] = new_graph  # 添加到输出
                        cursor += 1
                        # if cursor == stop:
                        breakFlag = True

        rt = rt.tolist()
        n = []
        for i in range(len(rt)):
            k = [0, 0, 0, rt[i]]
            n.append(k)
        return rt

    def get_highest(self, graphs):
        graphs = np.array(graphs)
        k = graphs.max(axis=0)
        kk = k.max(axis=0)
        return kk[1]


class Calculator(threading.Thread, place):

    def __init__(self):
        super(Calculator, self).__init__()
        self.gridScale = 2  # 遍历时使用的栅格的放大倍数
        self.gridX = 40  # 排布时的X范围
        self.gridY = 50  # Y

        self.data = {}
        self.score = []
        self.pop = pd.DataFrame()
        self.pop_LEN = 0
        self.gen_LEN = None  # 一个个体的基因长度
        self.gen1 = np.zeros(0) # 基因1：位置基因
        self.gen2 = np.zeros(0) # 基因2：旋转基因

        self.CROSS_LIMIT = 2  # 繁衍次数
        self.SHEEP_AMOUNT = 10  # 个体数量
        self.CROSS_RATE = 0.6
        self.MUTATE_RATE = 0.7
        self.CUT_POINT = 5
        self.MUTATE_POINT = 7
        self.plt = plt

    def init_pop(self):
        # 初始化种群
        index = [np.arange(self.SHEEP_AMOUNT).repeat(2), np.array(['A', 'B'] * self.SHEEP_AMOUNT)]
        self.pop = pd.DataFrame([self.gen1, self.gen2] * self.SHEEP_AMOUNT, index=index)  # <基因名
        self.initGrid()
        # 初始化基因
        self.pop = self.pop.swaplevel()  # 翻转alias使AB在前
        self.pop.loc['A'] = np.array([np.random.permutation(range(self.gen_LEN)) for _ in range(self.SHEEP_AMOUNT)])
        self.pop.loc['B'] = np.array(
            [[random.random() * pi for _ in range(self.gen_LEN)] for _ in range(self.SHEEP_AMOUNT)])  # 弧度
        self.pop = self.pop.swaplevel()
        print(self.pop)

    # 交叉：将父母的染色体OBX交叉
    def crossover(self, he, she):
        cut_point = np.array(random.sample(range(self.gen_LEN), self.CUT_POINT))    # 基因探针

        A = he[cut_point].loc['A']
        her_A = she.loc['A', she.loc['A'].isin(A)]   # 定位女方对应基因的位置
        her_B = she.loc['B', she.loc['A'].isin(A)]
        for i in cut_point: # 切除男方基因
            he.pop(i)
        index = list(range(self.gen_LEN))
        for i in her_A.index:
            index.remove(i) # 女方剩下基因的位置
        # A融合
        k = pd.Series(he.loc['A'].values, index=index)  # 男方剩下基因准备好
        her_A = her_A.reindex(range(self.gen_LEN)).fillna(k)    # 融合
        # B融合
        k = pd.Series(he.loc['B'].values, index=index)
        her_B = her_B.reindex(range(self.gen_LEN)).fillna(k)

        child = pd.DataFrame([her_A, her_B])
        return child

    # 变异：3轮循环，每轮交换一对位置
    def mutate(self, child):
        if random.random() < self.MUTATE_RATE:
            counter = 0
            while counter < self.MUTATE_POINT:
                print(child)
                waiting()
                # 基因重组
                gene_vehicle = np.array(random.sample(range(self.gen_LEN), 2))
                child[gene_vehicle] = child[gene_vehicle[::-1]]
                # 基因突变
                gene_needle = np.random.randint(self.gen_LEN)
                if child[gene_needle] not in [0, self.gen_LEN]:
                    child[gene_needle] = -child[gene_needle]
                counter += 1

        return child

    def select(self):
        base = self.rects.copy()
        self.score = []
        for dna in self.pop:
            # dna:[ 9  6  2  5  1  7  8 11 10  3  4]
            grid = self.grids.copy()
            rects = np.array([base[i] for i in
                              dna])  # [[[0, 0], [12, 0], [12, 1], [0, 1]], [[0, 0], [9, 0], [9, 5], [0, 5]], [[0, 0], [2, 0], [2, 11], [0, 11]], [[0, 0], [8, 0], [8, 5], [0, 5]], [[0, 0], [2, 0], [2, 6], [0, 6]], [[0, 0], [8, 0], [8, 2], [0, 2]], [[0, 0], [7, 0], [7, 9], [0, 9]], [[0, 0], [2, 0], [2, 9], [0, 9]], [[0, 0], [12, 0], [12, 13], [0, 13]], [[0, 0], [13, 0], [13, 13], [0, 13]], [[0, 0], [12, 0], [12, 6], [0, 6]]]
            new_rect = self.FF_place(grid,
                                     rects)  # FF摆放 [[[0, 0], [8, 0], [8, 2], [0, 2]], [[8, 0], [10, 0], [10, 9], [8, 9]], [[10, 0], [22, 0], [22, 1], [10, 1]], [[22, 0], [31, 0], [31, 5], [22, 5]], [[10, 1], [22, 1], [22, 7], [10, 7]], [[31, 1], [33, 1], [33, 12], [31, 12]], [[10, 7], [23, 7], [23, 20], [10, 20]], [[23, 12], [35, 12], [35, 25], [23, 25]], [[24, 12], [26, 12], [26, 18], [24, 18]], [[0, 13], [7, 13], [7, 22], [0, 22]], [[1, 13], [9, 13], [9, 18], [1, 18]]]

            # # 显示种群中的个体
            # n = []
            # for i in range(len(new_rect)):
            #     k = [0, 0, 0, new_rect[i]]
            #     n.append(k)
            # print(n)
            height = self.get_highest(new_rect)  # 得到每个种群的高度
            self.score.append(height)  # [19, 19, 20, 22, 23, 24, 24, 24, 25, 25, 23]

        self.score = sorted(enumerate(self.score), key=lambda x: x[1])
        pop = []
        mean = 0
        for i in range(self.SHEEP_AMOUNT):
            num = self.score[i][0]
            score = self.score[i][1]
            mean += score / self.SHEEP_AMOUNT
            pop.append(self.pop[num])

        self.pop = np.array(pop)
        self.show(mean)

        # print('score', self.score)
        # print('pop', self.pop)

    def select_tris(self, pop):
        pass

    def show(self, number):
        self.plt.figure(1)
        self.plt.pause(0.01)
        self.plt.plot(time.time(), number, '.')

    def get_popG(self, pop):
        graphs = []
        for i in pop:
            graph = self.rects[i]
            graphs.append(graph)
        return graphs

    def downloadData(self, data):  # [[4, array([[0. , 0. ],[4.8, 0. ],[8. , 3.2]]), array([4.267, 1.067]), array([4.267, 1.067])], [7..
        self.gen_LEN = len(data)
        for i in data:
            alias = i[0]
            graph = i[1]
            geo_core = i[2]
            catch_core = i[3]
            self.data[alias] = graph
        self.gen1 = np.zeros(self.gen_LEN)  # np.array([np.random.permutation(range(self.gen_LEN)) for _ in range(self.SHEEP_AMOUNT)])
        self.gen2 = np.zeros(self.gen_LEN)  # np.array([random.random() * pi for _ in range(self.gen_LEN)])  # 弧度
        # 初始化种群
        self.init_pop()

    def run(self) -> None:
        counter = 0
        self.plt.ion()

        self.pop_LEN = len(self.pop.index) / 2 -1 # 种群个体数
        while counter <= self.CROSS_LIMIT:
            print('----------第', counter, '次----------')

            sex_pool = list(range(self.SHEEP_AMOUNT))
            random.shuffle(sex_pool)    # 交叉前要打乱一下
            for _he in sex_pool:
                if random.random() < self.CROSS_RATE:   # <<<<<<<这里概率不行
                    # 发生交配
                    he = self.pop.loc[_he]
                    sex_pool.remove(_he)   # 将他自己去掉
                    _she = random.choice(sex_pool)
                    she = self.pop.loc[_she]
                    # sex_pool.remove(_she)   # 还是允许重复交配
                    # 交叉
                    child = self.crossover(he, she)
                    print(_he, '-', _she)
                    print(child)
                    # 变异
                    child = self.mutate(child)

                    # self.pop = self.pop.append(child)
            print(self.pop)

            waiting()
            # 将子代放入种群中
            # 淘汰

            counter += 1

        # label = min(self.score, key=lambda x:x[1])[0]
        you = self.pop[0]
        m = self.get_popG(you)
        m = self.FF_place(self.grids, np.array(m))
        n = []
        for i in range(len(m)):
            k = [0, 0, 0, m[i]]
            n.append(k)
        print('\n', '---------- end ----------')
        print(n)
        self.plt.ioff()
        self.plt.pause(0)


def waiting():
    k = input('pending...')

if __name__ == '__main__':
    data = data_bridge.load_from_MB('/home/suu/Desktop/input.csv')
    # tris = []
    # for i in data:
    #     if len(i[1]) == 3:
    #         tris.append(i)

    c1 = Calculator()
    c1.downloadData(data)
    c1.start()


